package services

import (
	"context"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"github.com/gocolly/colly/v2"
	"github.com/gocolly/colly/v2/extensions"
	"github.com/panjf2000/ants/v2"
	"github.com/sirupsen/logrus"
	"gorm.io/gorm"
	"net"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"
)

func Nba(url, proxyUrl string, db *gorm.DB, log *logrus.Logger) {
	c := colly.NewCollector(
		colly.MaxDepth(1),
		//colly.Debugger(&debug.LogDebugger{}),
	)
	extensions.RandomUserAgent(c)
	c.Limit(&colly.LimitRule{
		RandomDelay: 500 * time.Millisecond,
		Parallelism: 10,
	})
	c.OnRequest(func(request *colly.Request) {
		request.Headers.Set("Accept-Language", "en,zh-TW;q=0.9,zh;q=0.8")
	})

	resp := RandomConn(proxyUrl, url)
	defer resp.NetConn.Close()

	c.WithTransport(&http.Transport{
		DialContext: func(ctx context.Context, network, url string) (net.Conn, error) {
			return resp.NetConn, nil
		},
		MaxIdleConns:          100,
		IdleConnTimeout:       5 * time.Second,
		TLSHandshakeTimeout:   3 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,
	})
	defer ants.Release()
	var wg sync.WaitGroup
	pool, _ := ants.NewPool(30)
	defer pool.Release()
	task := func(url, proxyFile string, wg *sync.WaitGroup, db *gorm.DB, log *logrus.Logger) func() {
		return func() {
			defer wg.Done()
			NbaPlayerInfo(url, proxyFile, db, log)
		}
	}

	c.OnHTML("table.table.table-sm.table-striped", func(e *colly.HTMLElement) {
		e.ForEach("tr", func(i int, element *colly.HTMLElement) {
			link := element.DOM.Find("td:nth-of-type(1)").Find("a")
			href, _ := link.Attr("href")
			if href != "" {
				//log.Infof("href: %s", href)
				wg.Add(1)
				pool.Submit(task(href, proxyUrl, &wg, db, log))
				// TODO debug
				return
			}
		})
		wg.Wait()
	})

	c.Visit(url)
}

func NbaPlayerInfo(url, proxyUrl string, db *gorm.DB, log *logrus.Logger) {
	log.Infof("url: %s", url)
	c := colly.NewCollector(
		colly.MaxDepth(1),
		//colly.Debugger(&debug.LogDebugger{}),
	)
	extensions.RandomUserAgent(c)
	c.Limit(&colly.LimitRule{
		RandomDelay: 500 * time.Millisecond,
		Parallelism: 10,
	})
	c.OnRequest(func(request *colly.Request) {
		request.Headers.Set("Accept-Language", "en,zh-TW;q=0.9,zh;q=0.8")
	})

	resp := RandomConn(proxyUrl, url)
	defer resp.NetConn.Close()

	c.WithTransport(&http.Transport{
		DialContext: func(ctx context.Context, network, url string) (net.Conn, error) {
			return resp.NetConn, nil
		},
		MaxIdleConns:          100,
		IdleConnTimeout:       5 * time.Second,
		TLSHandshakeTimeout:   3 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,
	})
	c.OnHTML("div.card.pb-2[itemscope] table.table.table-striped.table-sm", func(e *colly.HTMLElement) {
		//all, _ := e.DOM.Html()
		//os.WriteFile("./tmp/player.html", []byte(all), 0755)
		jj := 0
		filePath := "./tmp/" + strings.Replace(url, "https://www.2kratings.com/teams/", "", -1) + ".txt"
		file, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
		if err != nil {
			log.Printf("Error opening file %s: %v", filePath, err)
			return
		}
		defer file.Close()
		e.ForEach("tbody tr", func(i int, element *colly.HTMLElement) {
			//link := element.DOM.Find("td:nth-of-type(1)").Find("span.entry-b")
			//name, _ := link.Attr("title")
			//log.Infof("link: %#v", link.Text())
			//html, _ := element.DOM.Html()
			td := element.DOM.Find("td:nth-of-type(2)")
			name, _ := td.Find("span.entry-bg.mr-1").Find("img").Attr("title")
			info := td.Find("span.optional-info").Text()
			info = strings.ReplaceAll(info, "|", "")
			info = strings.TrimSpace(info)
			//html, _ := element.DOM.Html()
			//os.WriteFile("./tmp/"+strconv.Itoa(i)+".html", []byte(html), 0755)
			score := element.DOM.Find("td:nth-of-type(3)").Find("span.attribute-box").Text()

			hmap := []string{}

			td.Find("a").Each(func(i int, selection *goquery.Selection) {
				title, _ := selection.Attr("href")
				if strings.Contains(title, "/lists/") && !strings.Contains(selection.Text(), "'") {
					hmap = append(hmap, selection.Text())
				}
			})
			if name != "" {
				jj++
				str := fmt.Sprintf("%s|%s|%s|%s", name, score, strings.Join(hmap, "/"), info)
				log.Info(str)
				_, err = file.WriteString(str + "\n")
				if err != nil {
					log.Printf("Error writing to file %s: %v", filePath, err)
					return
				}
			}
			return
		})
	})
	c.Visit(url)
}
